package com.maiko.maikoaiagent.advisor;

import org.springframework.ai.chat.client.advisor.api.*;
import reactor.core.publisher.Flux;

import java.util.HashMap;
import java.util.Map;

/**
 * ReReadingAdvisor 是一个拦截器，用于对用户请求进行“重读”处理。
 * 它实现了 CallAroundAdvisor 和 StreamAroundAdvisor 接口，分别对同步和流式调用进行统一的预处理。
 *
 * 主要功能：在模型处理前，修改用户输入，将其封装为“再次阅读”的格式，帮助模型更深入地理解问题。
 *
 *
 * 思路：
 * 它这个是怎么来的呢，你自己写是不是一头雾水？你别自己去想，这个东西你去看源码，直接把SimpleLoggerAdvisor拉过来
 * 然后对着SimpleLoggerAdvisor改即可。
 *
 * Q：为什么这个拦截器没用，用了自定义拦截器呢？
 * A：你这个让用户消息重复两遍，那不就是让用户的token翻倍了吗，那你用的钱就变多了。
 */
public class ReReadingAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {

    /**
     * 请求预处理逻辑。
     *
     * @param advisedRequest 原始请求对象，包含用户文本和参数
     * @return 返回一个新的 AdvisedRequest，其中用户文本被修改为“重读提示”格式，并添加了额外参数
     */
    private AdvisedRequest before(AdvisedRequest advisedRequest) {
        // 拷贝用户参数，防止修改原始参数对象
        Map<String, Object> advisedUserParams = new HashMap<>(advisedRequest.userParams());

        // 添加一个新参数，用于保留用户原始输入文本（供后续处理或调试用）
        advisedUserParams.put("re2_input_query", advisedRequest.userText());

        // 创建一个新的请求对象，替换 userText 为“重读”提示结构，提升模型的理解能力
        return AdvisedRequest.from(advisedRequest)
                .userText("""
                    {re2_input_query}
                    Read the question again: {re2_input_query}
                    """)
                .userParams(advisedUserParams)
                .build();
    }

    /**
     * 同步调用的拦截处理。
     * 在调用主逻辑之前，先对请求进行预处理（重写用户输入）。
     *
     * @param advisedRequest 原始请求
     * @param chain 调用链对象
     * @return 返回处理结果
     */
    @Override
    public AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {
        // 对请求做“重读”处理，然后交给后续处理链执行
        return chain.nextAroundCall(this.before(advisedRequest));
    }

    /**
     * 流式调用的拦截处理。
     * 与 aroundCall 类似，但用于支持响应式编程（如 Flux 流）
     *
     * @param advisedRequest 原始请求
     * @param chain 调用链对象
     * @return 返回响应式结果流
     */
    @Override
    public Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {
        return chain.nextAroundStream(this.before(advisedRequest));
    }

    /**
     * 设置当前拦截器的执行顺序。
     * 数字越小，优先级越高。0 表示最高优先级（默认执行最早）。
     *
     * @return 优先级数字
     */
    @Override
    public int getOrder() {
        return 0;
    }

    /**
     * 返回当前拦截器的名称（类名），用于日志记录或识别用途。
     *
     * @return 拦截器名称
     */
    @Override
    public String getName() {
        return this.getClass().getSimpleName();
    }
}

